/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <windows.h>
#include "ssi_librarymanager.h"
#include "SSI_ScriptAPI.h"

#include <algorithm>
using std::find;

typedef int (*FUNCPROC)(CEngine*); 
typedef int (*KEYPROC)(const char*, ssi_stream* out); 

CLibraryObject::CLibraryObject(){
	id = 0;
	LoadCount = 0;
	Name = "";
}

CLibraryObject::~CLibraryObject(){
}

int CLibraryObject::Free(){
	if(id){
		FreeLibrary(id);
	}


	id = 0;
	Name = "";
	return 1;
}


int CLibraryObject::Load(CEngine *theEngine){
	FUNCPROC Func;
  KEYPROC KeyProc;

//	if(LoadCount <= 0){
		LoadCount = 0;
    SetLastError(0);
		id = LoadLibrary(Name.c_str());
    DWORD dwErr = GetLastError();
		if(!id){
      FILE* FH = fopen("LibMgrMessages.log", "a");
			//printf("Error: Could not load DLL: %s (See Externals.dat)\n", Name.c_str());
      fprintf(FH, "Error: Could not load DLL: %s (See Externals.dat) - Error Code: %d\n", Name.c_str(), dwErr);
      fclose(FH);
			return 0;
		}
//	}
	
  if(Key.length() > 0){
    KeyProc = (KEYPROC)GetProcAddress(id, "CheckKey");
    if(KeyProc){
      int iRes = (KeyProc)(Key.c_str(), theEngine->GetOutStream());
      if(iRes <= 0){
        FILE* FH = fopen("LibMgrMessages.log", "a");
        fprintf(FH, "Error: Registration failed: %s\n", Name.c_str());
        fclose(FH);
		    FreeLibrary(id);
		    id = 0;
		    return 0;
      }
    }
  }

  Func = (FUNCPROC)GetProcAddress(id, "RegisterFunctions");
	if(!Func){
		
      FILE* FH = fopen("LibMgrMessages.log", "a");
			//printf("Error: RegisterFunctions not found in %s\n", Name.c_str());
      fprintf(FH, "Error: RegisterFunctions not found in %s\n", Name.c_str());
      fclose(FH);

		FreeLibrary(id);
		id = 0;
		return 0;
	}
	(Func)(theEngine);
	LoadCount++;
	return LoadCount;
}

int CLibraryObject::Unload(CEngine* theEngine){
	FUNCPROC Func;
	Func = (FUNCPROC)GetProcAddress(id, "CleanUp");
	if(Func){
		(Func)(theEngine);
	}

	LoadCount--;
	//if(LoadCount <= 0){
	//	FreeLibrary(id);
	//	id = 0;
	//}
	return LoadCount;
}

int CLibraryObject::GetLoadCount(){
	return LoadCount;
}

bool CLibraryObject::operator<(const CLibraryObject& Other){
	return Name<Other.Name;
}

bool CLibraryObject::operator ==(const CLibraryObject& Other)
{
	if(Name == Other.Name){
		return 1;
	}
	return 0;
}




CLibraryManager::CLibraryManager(void)
{
}

CLibraryManager::~CLibraryManager(void)
{
	Factory_ClearData();
	vector<CLibraryObject>::iterator itor;
	for(itor = LibraryList.begin(); itor != LibraryList.end(); itor++){
		(*itor).Free();
		LibraryList.erase(itor, itor);
	}

}

int CLibraryManager::LoadDLLs(CEngine* theEngine)
{
	return 0;
}

int CLibraryManager::LoadDLLs(CEngine* theEngine, const char* ExternalFile){
	File aFile;
	String aStr;

	if(!aFile.Open(ExternalFile, "r")){
		
      FILE* FH = fopen("LibMgrMessages.log", "a");
			//printf("Error: RegisterFunctions not found in %s\n", Name.c_str());
      fprintf(FH, "Warning: %s (external DLL list) not found\n", ExternalFile);
      fclose(FH);
		return 0;
	}

  String sKey = "";
	while(aFile.ReadLine(aStr) >= 0){

    if(aStr.Parse("?", sKey) >= 0){
      sKey.Trim();
      aStr.Trim();
    }

		theEngine->SetPackageName(aStr.Str());
		LoadDLL(aStr.Str(), sKey.Str(), theEngine);
    sKey="";
	}
	return 1;
}

int CLibraryManager::LoadDLL(const char* Name, const char* Key, CEngine* theEngine){
	CLibraryObject anObj;
	anObj.Name = Name;
  anObj.Key = Key;
	vector<CLibraryObject>::iterator itor;
	if((itor = find(LibraryList.begin(), LibraryList.end(), anObj)) != LibraryList.end()){
		(*itor).Key = Key;
    return (*itor).Load(theEngine);
	}

	if(anObj.Load(theEngine)){
		LibraryList.push_back(anObj);
		return 1;
	}
	return 0;
}

int CLibraryManager::FreeDLLs(CEngine* theEngine){
	vector<CLibraryObject>::iterator itor;
	for(itor = LibraryList.begin(); itor != LibraryList.end(); itor++){
		(*itor).Unload(theEngine);
	}
	return 1;
}


